package com.medical.admin.sys.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.medical.admin.sys.common.dto.AdminDto;
import com.medical.admin.sys.common.utils.ShiroUtils;
import com.medical.admin.sys.entity.Admin;
import com.medical.admin.sys.mapper.AdminMapper;
import com.medical.admin.sys.service.AdminService;
import com.qf.medical.ex.ServiceException;
import com.qf.medical.response.ResponseCode;
import com.qf.medical.uitils.BeanPageUtils;
import com.qf.medical.utils.BeanConvertUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.function.Supplier;

/*
 * @Date : 2024/4/26 下午9:54
 * @Created by Lang
 * @ProjectName : medical-appointment-registration
 */
@Service
public class AdminServiceImpl implements AdminService {

    @Resource
    private AdminMapper adminMapper;

    @Override
    public Integer modAdmin(AdminDto adminDto) {
        // 将传入的对象转化为实体类 用户名 账号 角色 手机号码 密码 是否启用
        Admin admin = BeanConvertUtils.convertTo(adminDto, Admin::new);
        // 查询加密盐
        LambdaQueryWrapper<Admin> eq = new QueryWrapper<Admin>().lambda().eq(Admin::getMarAdminId, admin.getMarAdminId());
        Admin oldAdmin = adminMapper.selectOne(eq);

        //判断新的admin和旧的admin用户名是否不相等，并且在数据库中没有其他相同的用户名（没改用户名）
        LambdaQueryWrapper<Admin> ne = new QueryWrapper<Admin>().lambda().eq(Admin::getMarAdminUsername, admin.getMarAdminUsername()).ne(Admin::getMarAdminId, admin.getMarAdminId());
        Admin haveUsername = adminMapper.selectOne(ne);
        //当前用户名改了并且数据库中已存在该用户名
        if (ObjectUtil.isNotEmpty(haveUsername)){
            throw new ServiceException(ResponseCode.ADMIN_USERNAME_IS_HAVE);
        }

        //判断是否修改了账号
        LambdaQueryWrapper<Admin> ne2 = new QueryWrapper<Admin>().lambda().eq(Admin::getMarAdminAccount, admin.getMarAdminAccount()).ne(Admin::getMarAdminId, admin.getMarAdminId());
        Admin haveAccount = adminMapper.selectOne(ne2);
        //当前用户名改了并且数据库中已存在该用户名
        if ( ObjectUtil.isNotEmpty(haveAccount)){
            throw new ServiceException(ResponseCode.ADMIN_ACCOUNT_IS_HAVE);
        }

        //判断电话是否重复
        LambdaQueryWrapper<Admin> ne3 = new QueryWrapper<Admin>().lambda().eq(Admin::getMarAdminPhone, admin.getMarAdminPhone()).ne(Admin::getMarAdminId, admin.getMarAdminId());
        Admin havePhone = adminMapper.selectOne(ne3);
        //当前用户名改了并且数据库中已存在该电话号码
        if (ObjectUtil.isNotEmpty(havePhone)){
            throw new ServiceException(ResponseCode.ADMIN_PHONE_IS_HAVE);
        }

        //根据加密盐设置密码
        String encryption = ShiroUtils.encryption(admin.getMarAdminPassword(), oldAdmin.getSalt());
        admin.setMarAdminPassword(encryption);

        return adminMapper.updateById(admin);
    }

    @Override
    public Integer add(AdminDto adminDto) {
        Admin admin = checkUsernameAndAccount(adminDto);
        // 雪花算法唯一id
        admin.setMarAdminId(IdUtil.getSnowflakeNextId());
        // 加密盐
        String salt = new SecureRandomNumberGenerator().nextBytes().toHex();
        // 加密
        String encryption = ShiroUtils.encryption(admin.getMarAdminPassword(), salt);
        admin.setSalt(salt);
        admin.setMarAdminPassword(encryption);
        return adminMapper.insert(admin);
    }

    //验证用户名或账号是否存在
    public Admin checkUsernameAndAccount(AdminDto adminDto) {
        Admin admin = BeanConvertUtils.convertTo(adminDto, Admin::new);
        if (ObjectUtil.isNotEmpty(adminMapper.selectByUsername(admin.getMarAdminUsername()))) {
            throw new ServiceException(ResponseCode.ADMIN_USERNAME_IS_HAVE);
        }

        if (ObjectUtil.isNotEmpty(adminMapper.selectByAccount(admin.getMarAdminAccount()))) {
            throw new ServiceException(ResponseCode.ADMIN_ACCOUNT_IS_HAVE);
        }
        return admin;
    }

    @Override
    public Page<AdminDto> list(String adminAccount, Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<Admin> lambda = new QueryWrapper<Admin>().lambda();
        //开启分页
        Page<Admin> adminPage = new Page<>(pageNum, pageSize);
        //排除自己
        //是否携带账号
        if (ObjectUtil.isNotEmpty(adminAccount)) {
            lambda.like(Admin::getMarAdminAccount, adminAccount);
        }

        adminPage = adminMapper.selectPage(adminPage, lambda);
        Page<AdminDto> page = new Page<>();

        Supplier<AdminDto> targetSupplier = AdminDto::new;
        return BeanPageUtils.convertPage(adminPage, page, targetSupplier);
    }

    @Override
    public Integer modStatus(Long adminId, Integer adminStatus) {
        Admin admin = new Admin();
        admin.setMarAdminId(adminId);
        admin.setMarAdminStatus(adminStatus);
        return adminMapper.updateById(admin);
    }

    @Transactional(rollbackFor = RuntimeException.class,timeout = 5)
    @Override
    public Integer delBatch(Long[] adminIds) {

        return adminMapper.delBatch(Arrays.asList(adminIds));
    }

    @Override
    public Integer del(Long adminId) {
        return adminMapper.update(new LambdaUpdateWrapper<Admin>().set(Admin::getMarAdminStatus, 0).eq(Admin::getMarAdminId, adminId));
    }

    @Override
    public AdminDto selectById(Long adminId) {
        Admin admin = adminMapper.selectById(adminId);
        return BeanConvertUtils.convertTo(admin, AdminDto::new);
    }

    @Override
    public Admin getAdminByAccount(String adminAccount) {
        LambdaQueryWrapper<Admin> eq = new LambdaQueryWrapper<Admin>().eq(Admin::getMarAdminAccount, adminAccount);
        return adminMapper.selectOne(eq);
    }

    @Override
    public AdminDto login(String adminAccount, String adminPassword) {
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(adminAccount,adminPassword);
        subject.login(token);
        return (AdminDto) SecurityUtils.getSubject().getPrincipals().getPrimaryPrincipal();
    }

    @Override
    public Integer rePassword(String adminId, String adminPassword) {
        //获取当前用户的加密盐
        LambdaQueryWrapper<Admin> eq = new LambdaQueryWrapper<Admin>()
                .eq(Admin::getMarAdminId, adminId);
        Admin admin = adminMapper.selectOne(eq);
        String encryption = ShiroUtils.encryption(adminPassword, admin.getSalt());
        LambdaUpdateWrapper<Admin> set = new LambdaUpdateWrapper<Admin>()
                .set(Admin::getMarAdminPassword, encryption).eq(Admin::getMarAdminId, adminId);

        return adminMapper.update(set);
    }
}
